package com.zmzncs.lmtc.common.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.zmzncs.lmtc.common.annotation.Idempotent;
import com.zmzncs.lmtc.common.util.ExceptionUtil;
import com.zmzncs.lmtc.common.util.JsonUtil;
import com.zmzncs.lmtc.common.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 日志切面
 */

@Aspect
@Component
@Slf4j
public class IdempotentAOP {

    //  请求队列
    private static List<String> requestCatch = new ArrayList();
    //  客户id + 请求路径
//    private String key = "";
    ThreadLocal<String> threadLocal = new ThreadLocal<>();

    @Pointcut("@annotation(com.zmzncs.lmtc.common.annotation.Idempotent)")
//    @Pointcut("execution(public * com.zmzncs.lmtc.module.*.controller.*.*(..))")
    public void idempotent(){}


    /**
     *  前置通知
     */
    @Before("idempotent()")
    public void doBefore(JoinPoint joinPoint) {
        String key = "";

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Idempotent idempotent = signature.getMethod().getAnnotation(Idempotent.class);
        String param = idempotent.param();

        //  获取request
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
        //  获取请求参数
        String requestBody = JsonUtil.objectToJson(joinPoint.getArgs());

        //  如果请求不需要token，则key请求地址+参数组成，否则key由客户id+请求地址+参数组成
        if(StringUtils.isNotBlank(param)){
            try {
                JSONArray array = JSONArray.parseArray(requestBody);
                JSONObject jsonObject = JSONObject.parseObject(array.get(0)+"");
                key  =  jsonObject.get(param)+"";
            } catch (Exception e) {
                e.printStackTrace();
                log.error("获取幂等key异常【{}】", e.getMessage());
                key = JwtUtil.getLoginUser(request).getCustomerId() + request.getRequestURI() + requestBody;
            }
        }else if(request.getHeader("token") == null){
            key = request.getRequestURI() + requestBody;
        } else {
            key = JwtUtil.getLoginUser(request).getCustomerId() + request.getRequestURI() + requestBody;
        }

        //  如果请求队列中已经包含，则拒绝请求
        if(requestCatch.contains(key)) {
            ExceptionUtil.businessException("请勿重复提交【" + key + "】");
        }

        threadLocal.set(key);
        requestCatch.add(key);
    }

    /**
     *  后置正常通知
     */
    @AfterReturning(returning = "ret", pointcut = "idempotent()")
    public void doAfterReturning(Object ret) {

    }

    /**
     *  后置异常通知
     */
    @AfterThrowing("idempotent()")
    public void throwss(JoinPoint joinPoint){

    }

    /**
     * 后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
     */
    @After("idempotent()")
    public void after(JoinPoint joinPoint){
        String key = threadLocal.get();
//        log.info("清除幂等key【{}】", key);
        requestCatch.remove(key);
    }

    /**
     * 环绕通知,环绕增强，相当于MethodInterceptor
     */
    @Around("idempotent()")
    public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {

        return joinPoint.proceed();
    }
}
